/* 
 * Autores:
 *      Jonathan Lopez  11106
 *      Jorge Martínez  11237
 * 
 * Archivo: Ruta.java
 * Última Revision: $Rev: 69 $
 *      Fecha: $Date: 2011-09-19 06:58:38 +0000 (Mon, 19 Sep 2011) $
 */

package Manejo.Transporte;

import Manejo.Transporte.Registros.*;
import Archivador.*;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;

/**
 * Representa un listado de Puertos por los cuales tiene que pasar un Barco.
 * Se maneja indirectamente a traves de un Viaje.
 * 
 * @author Jonathan López
 * @author Jorge Martinez
 * @see Viaje
 */
public class Ruta implements iArchivable
{
   
    private ArrayList<ID> puertos;
    private ArrayList<Date> tiempos;
    
    private RegPuertos registroPuertos;
    private final Registros registros;
    
    /**
     * Contructor de la Ruta
     * @param registroPuertos
     */
    public Ruta( Registros registros ){
        this.registroPuertos = registros.obtenerRegistroPuertos();
        this.registros = registros;
        
        puertos = new ArrayList<ID>();
        tiempos = new ArrayList<Date>();
    }
    
    /**
     * Agrega un nuevo Puerto a la Ruta. El Puerto tiene que existir en su
     * respectivo registro para ser agregado.
     * @param idPuerto ID del Puerto a agregar. Este se vuelve el último
     * puerto a seguir en la Ruta después de los anteriores.
     * @param tiempo Representa la cantidad de tiempo que se tardaría
     * el Barco de ir del Puerto anterior a este Puerto (en MILISEGUNDOS).
     * @return regresa true si el Puerto se pudo agregar, false en caso contrario
     * @see Calendar
     */
    public boolean agregarPuerto( ID idPuerto, long tiempoMS ){
        // Revisar que el puerto existe
        if( registroPuertos.obtenerPuerto( idPuerto ) == null )
            return false;
        
        // Agregar el puerto. Si este es el primero entonces se
        // toma que tiempo es 0
        if( puertos.isEmpty() ){
            puertos.add(idPuerto);
            tiempos.add( new Date(0) );
        } else {
            puertos.add(idPuerto);
            tiempos.add( new Date(tiempoMS) );
        }
        
        return true;
    }
    
    /**
     * Agrega un nuevo Puerto a la Ruta. El Puerto tiene que existir en su
     * respectivo registro para ser agregado.
     * @param idPuerto ID del Puerto a agregar. Este se vuelve el último
     * puerto a seguir en la Ruta después de los anteriores.
     * @param tiempo Representa la cantidad de tiempo que se tardaría
     * el Barco de ir del Puerto anterior a este Puerto en días.
     * @return regresa true si el Puerto se pudo agregar, false en caso contrario
     * @see Calendar
     */
    public boolean agregarPuerto( ID idPuerto, float tiempoDias ){
        // Convertir de dias a milisegundos
        long tiempoTotal = (long)(tiempoDias * 24.0f * 60.0f * 60.0f * 1000.0f);
        return agregarPuerto( idPuerto, tiempoTotal );
    }
    
    /**
     * Regresa un arreglo con todos los Puertos que componen la Ruta
     * @return Array de Puertos
     */
    public ID[] obtenerPuertos(){
        return puertos.toArray( new ID[0] );
    }
    
    /**
     * Regresa un arreglo con los tiempos con los cuales se registraron los
     * Puertos
     * @return Array de Date
     */
    public Date[] obtenerTiempos(){
        return tiempos.toArray( new Date[0] );
    }

    /**
     * Regresa una representación String de la Ruta con los puertos y tiempos
     * que se registraron.
     * @return representación String
     */
    @Override
    public String toString()
    {
        String ret = "Ruta{";
        
        // Obtener nombres de los Puertos
        for (int i = 0; i < puertos.size(); i++) {
            ID idPuerto = puertos.get(i);
            
            if( i == 0 ){
                ret += registroPuertos.obtenerNombre(idPuerto);
            }
            else{
                float tiempoDias = tiempos.get(i).getTime() 
                        / 1000.0f   // a segundos
                        / 60.0f     // a minutos
                        / 60.0f     // a horas
                        / 24.0f;    // a dias
                ret += "; " + registroPuertos.obtenerNombre(idPuerto) +
                        ":" + tiempoDias + " dias";
            }
        }
        
        return ret + '}';
    }

    /**
     * Regresa un línea de texto para ser guardada en un medio persistente.
     * @return String
     * @see iArchivable#guardar() 
     */
    @Override
    public String guardar()
    {
        // Orden: [Puerto|Tiempo]##... n
        int nPuertos = puertos.size();
        String linea = "";
        
        for (int n = 0; n != nPuertos; n++) {
            linea += "[" + puertos.get(n).guardar() + "|" +
                    tiempos.get(n).getTime() + "]" + separadorObjetos ;
        }
        
        return linea;
    }
    
    /**
     * Genera una nueva Ruta a partir de una línea de texto creada a través
     * del método guardar()
     * @param linea
     * @param registroPuertos
     * @return nueva Ruta a partir del String, o null si falla
     */
    public static Ruta parseRuta( String linea, Registros registros ){
        // Separar todos los objetos
        String[] objetos = linea.split(separadorObjetos);
        ArrayList<ID> puertos = new ArrayList<ID>();
        ArrayList<Date> tiempos = new ArrayList<Date>();
        
        for( String obj: objetos ){
            if( obj.equals("") )
                continue;
            
            // Validar cada objeto
            if( !Util.validarLinea(obj) )
                return null;
            String srPuerto =  Util.eliminarExtremos(obj);
            if( srPuerto.equals("") )
                return null;
            
            // Separar el puerto y tiempo
            String partes[] = srPuerto.split( "\\|" );
            int cantidadPartes = 3;
            if( partes.length != cantidadPartes )
                return null;
            
            ID _puerto = ID.parseID(partes[0] + "|" + partes[1]);
            Date _tiempo = new Date( Long.parseLong(partes[2]) );
            if( _puerto.equals(ID.idNulo) )
                // DEBUG
                System.out.println("** ID MALO **");
            else{
                puertos.add( _puerto );
                tiempos.add(_tiempo);
            }
        }
        
        // Validar los tamannos de los arreglos
        if( puertos.size() != tiempos.size() )
            return null;
        
        // Crear la nueva Ruta
        Ruta nuevaRuta = new Ruta( registros );
        nuevaRuta.puertos = puertos;
        nuevaRuta.tiempos = tiempos;
        
        return nuevaRuta;
    }
    
    
    /**
     * Punto de entrada para las pruebas unitarias de Ruta.
     * @param args
     */
    public static void main( String[] args ){
        int pruebas = 10;
        int fallos = 0;
        java.util.Random gen = new java.util.Random();
        Registros registros = new Registros();
        
        RegPuertos registroPuertos = registros.obtenerRegistroPuertos();
        RegRutas registroRutas = registros.obtenerRegistroRutas();
        
        // Generar los puertos de prueba
        int cantidadPuertos = 25;
        ID[] puertos = new ID[cantidadPuertos];
        for (int i = 0; i != cantidadPuertos; i++) {
            Localizacion l = new Localizacion( "GUATEMALA, CA", 
                    gen.nextDouble(), gen.nextDouble() );
            Puerto p = new Puerto(l, registros );
            puertos[i] = registroPuertos.agregarPuerto(p, Integer.toString(gen.nextInt()) );
        }
        
        for (int n = 0; n != pruebas; n++) {
            Ruta ruta = new Ruta( registros );
            int nPuertos = gen.nextInt(cantidadPuertos);
            for (int i = 0; i != nPuertos; i++)
                ruta.agregarPuerto( puertos[gen.nextInt(cantidadPuertos)], gen.nextLong() );
            
            String linea = ruta.guardar();
            Ruta nuevaRuta = Ruta.parseRuta( linea, registros );
            
            boolean iguales = ruta.toString().equals(nuevaRuta.toString());
            if( !iguales )
                ++fallos;
            
            System.out.println(linea + " & " + iguales );
            System.out.println("\t" + ruta);
            System.out.println("\t" + nuevaRuta);
            
            // Guardar la ruta en el registro
            registroRutas.agregarRuta(ruta);
        }
        System.out.println("FALLOS: " + fallos);
        
        registroRutas.guardarTodo();
        Informador.guardarCambios();
    }
}
